package config

import (
	"crypto/rand"
	"fmt"

	"github.com/spf13/viper"
	//hexTracing "hexcloud.cn/histore/hex-pkg/hex-tracing"
	"math/big"
	"strconv"
	"strings"
	"time"
)

var v *viper.Viper
var Debug bool

var AccessTokenLifetime time.Duration
var PosTokenLifetime time.Duration
var RefreshTokenLifetime time.Duration
var PathPrefix string
var JWTSignSecret string

var RandPid *big.Int

func init() {
	RandPid, _ = rand.Int(rand.Reader, big.NewInt(100))
}

func init() {
	v = viper.New()

	v.SetConfigName("config")
	v.SetConfigType("yaml")
	v.AddConfigPath(".")
	v.SetEnvPrefix("HEX_OAUTH")
	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	v.AutomaticEnv()
	_ = v.ReadInConfig()
	dbDefault := map[string]string{
		"db.host":          "192.168.1.107",
		"db.port":          "5432",
		"db.user":          "postgres",
		"db.password":      "123456",
		"db.dbname":        "postgres",
		"db.max_idle_conn": "20",
		"db.max_open_conn": "100",
	}
	setDefault(v, dbDefault)

	redisDefault := map[string]string{
		"redis.host": "localhost",
		"redis.port": "6379",
		"redis.pwd":  "",
		"redis.db":   "0",
	}
	setDefault(v, redisDefault)

	ruleDefault := map[string]string{
		"passwd_rule.enable": "false",
	}
	setDefault(v, ruleDefault)

	sessionDefault := map[string]string{
		"session.key":      "hex_oauth",
		"session.secret":   "hex_oauth",
		"session.lifetime": strconv.Itoa(3600),
	}
	setDefault(v, sessionDefault)

	oauthDefault := map[string]string{
		"oauth.access_token_lifetime":  strconv.Itoa(3600 * 14),     // 14hour
		"oauth.refresh_token_lifetime": strconv.Itoa(3600 * 24 * 7), // 7day
		"oauth.pos_token_lifetime":     strconv.Itoa(3600 * 20),     // 20 hour
	}
	setDefault(v, oauthDefault)
	oauthConfig := LoadOauthConfig()
	AccessTokenLifetime = time.Second * time.Duration(oauthConfig.AccessTokenLifetime)
	PosTokenLifetime = time.Second * time.Duration(oauthConfig.PosTokenLifetime)
	RefreshTokenLifetime = time.Second * time.Duration(oauthConfig.RefreshTokenLifetime)
	PathPrefix = v.GetString("path_prefix")
	httpDefault := map[string]string{
		"web.host":         "localhost",
		"web.port":         "9090",
		"web.template_dir": "./template",
		"web.static_dir":   "./static",
	}
	setDefault(v, httpDefault)
	mode := v.Get("mode")
	if mode == "debug" {
		Debug = true
	} else {
		Debug = false
	}
	rpcConfig := map[string]string{
		"rpc.host": "0.0.0.0",
		"rpc.port": "9002",
	}
	setDefault(v, rpcConfig)

	traceDefault := map[string]string{
		"trace.service_name":  "oauth",
		"trace.agent_host":    "localhost",
		"trace.agent_port":    "6831",
		"trace.sample_type":   "const",
		"trace.sample_params": "1",
		"trace.disable":       "false",
	}
	setDefault(v, traceDefault)

	emailDefault := map[string]string{
		"email.host":    "smtp.exmail.qq.com",
		"email.port":    "465",
		"email.account": "no-reply@hex-tech.net",
		"email.pwd":     "Kw6LFRfzePQraLX",
	}
	setDefault(v, emailDefault)

	secret := v.GetString("jwt_sign_secret")
	if len(secret) == 0 {
		JWTSignSecret = "eyJ1c2VyX2lkIjo0MTg"
	} else {
		JWTSignSecret = secret
	}

	outerServiceDefault := map[string]string{
		"outer_service.metadata_addr": "localhost:5012",
	}
	setDefault(v, outerServiceDefault)

}

func LoadOuterServiceConfig() *OuterServiceConfig {
	return &OuterServiceConfig{
		MetadataAddr: v.GetString("outer_service.metadata_addr"),
	}
}

//func LoadTraceConfig() *hexTracing.HexTracerConfig {
//	return &hexTracing.HexTracerConfig{
//		ServiceName:  v.GetString("trace.service_name"),
//		AgentHost:    v.GetString("trace.agent_host"),
//		AgentPort:    v.GetString("trace.agent_port"),
//		SampleType:   hexTracing.TraceSampleType(v.GetString("trace.sample_type")),
//		SampleParams: v.GetFloat64("trace.sample_params"),
//		Disable:      v.GetBool("trace.disable"),
//	}
//}

func LoadOauthConfig() *OauthConfig {
	return &OauthConfig{
		AccessTokenLifetime:  v.GetInt64("oauth.access_token_lifetime"),
		RefreshTokenLifetime: v.GetInt64("oauth.refresh_token_lifetime"),
		PosTokenLifetime:     v.GetInt64("oauth.pos_token_lifetime"),
	}
}

func LoadDatabaseConfig() *DatabaseConfig {
	dbConfig := &DatabaseConfig{
		Host:         v.GetString("db.host"),
		Port:         v.GetInt("db.port"),
		User:         v.GetString("db.user"),
		Password:     v.GetString("db.password"),
		DatabaseName: v.GetString("db.dbname"),
		MaxIdleConns: v.GetInt("db.max_idle_conn"),
		MaxOpenConns: v.GetInt("db.max_open_conn"),
	}
	return dbConfig
}

func LoadSessionConfig() *SessionConfig {
	sessionConfig := &SessionConfig{
		Secret:   v.GetString("session.secret"),
		Key:      "hex_oauth",
		LifeTime: v.GetInt("session.lifetime"),
	}
	return sessionConfig
}

func LoadPGArgs() string {
	dbConfig := LoadDatabaseConfig()
	args := fmt.Sprintf(
		"sslmode=disable host=%s port=%d user=%s password='%s' dbname=%s timezone='Asia/Shanghai'",
		dbConfig.Host,
		dbConfig.Port,
		dbConfig.User,
		dbConfig.Password,
		dbConfig.DatabaseName,
	)
	return args
}

func LoadRedisConfig() *RedisConfig {
	redisConfig := &RedisConfig{
		Host: v.GetString("redis.host"),
		Port: v.GetString("redis.port"),
		DB:   v.GetInt("redis.db"),
		Pwd:  v.GetString("redis.pwd"),
	}
	return redisConfig
}

func LoadHTTPConfig() *HTTPConfig {
	httpConfig := &HTTPConfig{
		Host:        v.GetString("web.host"),
		Port:        v.GetString("web.port"),
		TemplateDir: v.GetString("web.template_dir"),
		StaticDir:   v.GetString("web.static_dir"),
		Address:     v.GetString("web.host") + ":" + v.GetString("web.port"),
	}
	return httpConfig
}

func LoadSystemAccessTokens() []string {
	tokensStr := v.GetString("system.access_tokens")
	return strings.Split(tokensStr, ",")
}

func LoadRpcConfig() *RPCConfig {
	rpcConfig := &RPCConfig{
		Host: v.GetString("rpc.host"),
		Port: v.GetString("rpc.port"),
	}
	return rpcConfig
}

func LoadEmailConfig() *EmailConfig {
	emailConfig := &EmailConfig{
		SMTPHost: v.GetString("email.host"),
		SMTPPort: v.GetInt("email.port"),
		Account:  v.GetString("email.account"),
		Pwd:      v.GetString("email.pwd"),
	}
	return emailConfig
}


func LoadPassWdRuleConfig() *PassWdRuleConfig {
	ruleConfig := &PassWdRuleConfig{
		Enable: v.GetBool("passwd_rule.enable"),
	}
	return ruleConfig
}
